/******************************************************************************* 
 * Copyright (C) 2012-2015 Microfountain Technology, Inc. All Rights Reserved. 
 * 
 * Unauthorized copying of this file, via any medium is strictly prohibited.   
 * Proprietary and confidential
 * 
 * Last Modified: 2015-9-22 16:34:40
 ******************************************************************************/
package cn.com.xy.sms.sdk.db;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import cn.com.xy.sms.sdk.Iservice.OnlineUpdateCycleConfigInterface;
import cn.com.xy.sms.sdk.constant.Constant;
import cn.com.xy.sms.sdk.db.bizport.BizportDBManager;
import cn.com.xy.sms.sdk.db.entity.JarSubInfoManager;
import cn.com.xy.sms.sdk.db.entity.SysParamEntityManager;
import cn.com.xy.sms.sdk.dex.DexUtil;
import cn.com.xy.sms.sdk.log.LogManager;
import cn.com.xy.sms.sdk.service.pubId.ParsePhonePubIdService;
import cn.com.xy.sms.sdk.util.FileUtils;
import cn.com.xy.sms.sdk.util.InitUtil;
import cn.com.xy.sms.sdk.util.StringUtils;
/*SDK-627 hewengao/20160929 start*/
import java.util.Map;
import java.util.Set;
import cn.com.xy.sms.sdk.threadpool.SmartSmsThreadPoolManager;
/*SDK-627 hewengao/20160929 end*/

/*SDK-633 hewengao 20161009 start*/
import android.os.Process;
/*SDK-633 hewengao 20161009 end*/

/*SDK-674 hewengao 20161114 start*/
import cn.com.xy.sms.sdk.util.DuoquUtils;
/*SDK-674 hewengao 20161114 end*/
public class ParseItemManager {

    public static final int NORMAL = 0;
    public static final int NEEDDEL = -1;
    public static final int INITTAG = -2;
    public static final int REGEX_TYPE_SCENE = 1;// 1:情景
    public static final int REGEX_TYPE_AD = 2;// 2:广告

    public static final String SCENE_ID = "scene_id";
    public static final String MATCH_ID = "match_id";
    public static final String REGEX_TEXT = "regex_text";
    public static final String REGEX_TYPE = "regex_type";
    public static final String VERSION_CODE = "version_code";
    public static final String STATE = "state";// 0为正常状态，-1为待删除，-2为初始化临时标记
    public static final String LAST_USE_TIME = "last_use_time";//最后一次使用的时间

    public static final String TABLE_NAME = "tb_regex";

    public static final String DROP_TABLE = " DROP TABLE IF EXISTS "
            + TABLE_NAME;
    public static final String CREATE_TABLE = "create table  if not exists "
            + TABLE_NAME + " ("

            + SCENE_ID + " TEXT," + MATCH_ID + " TEXT," + REGEX_TEXT + " TEXT,"
            + VERSION_CODE + " TEXT," + REGEX_TYPE + " INTEGER  DEFAULT '0',"
            + LAST_USE_TIME + " INTEGER  DEFAULT '0',"
            + STATE + " INTEGER  DEFAULT '0' " + ")";

    public static final String CREATE_INDEX = "create index if not exists indx_s_m on "
            + TABLE_NAME + " (" + SCENE_ID + "," + MATCH_ID + ")";
    /*SDK-627 hewengao/20160929 start*/
    public static final String CREATE_INDEX_SID= "create index if not exists indx_s on "
            + TABLE_NAME + " (" + SCENE_ID  + ")";
    /*SDK-627 hewengao/20160929 end*/
    public static final String ADD_LAST_USE_TIME = "ALTER TABLE "
            + TABLE_NAME + " ADD COLUMN last_use_time INTEGER DEFAULT '0'";

    static boolean isInitData = false;

    public static boolean isInitData() {
        if (!isInitData) {
            isInitData = SysParamEntityManager.getLongParam(
                    "init_xiaoyuan_sdk", 0, Constant.getContext()) == 1;
        }
        return isInitData;
    }

    private static boolean isCheckHasData = false;

    /* SDK-695 huangzhiqiang 20161207 begin */
    private static long mLastCheckDatabaseIsCorruptTime = 0;

    /**
     * 是否需要检查正则库已损坏，5分钟内不重复检查
     * 
     * @return
     */
    private static boolean needCheckDatabaseIsCorrupt() {
        return System.currentTimeMillis() > (mLastCheckDatabaseIsCorruptTime + 300000);
    }
    /* SDK-695 huangzhiqiang 20161207 end */

    public static void checkHasData() {
        /* SDK-695 huangzhiqiang 20161207 begin */
        // 正则库损坏后删除损坏文件并重新初始化脚本数据
        if (needCheckDatabaseIsCorrupt() && databaseIsCorrupt()) {
            mLastCheckDatabaseIsCorruptTime = System.currentTimeMillis();
            deleteCorruptFile();
            InitUtil.reInitAlgorithm(Constant.getContext(), null);
            return;
        }
        /* SDK-695 huangzhiqiang 20161207 end */
        if (isCheckHasData) {
            return;
        }
        isCheckHasData = true;
        Thread th = new Thread() {
            @Override
            public void run() {
                this.setName("xiaoyuan");
                XyCursor xyCursor = null;
                try {
                    xyCursor = BizportDBManager.query(false, TABLE_NAME,
                            new String[] { REGEX_TEXT }, null, null, null,
                            null, null, "1");
                    if ((xyCursor != null && xyCursor.getCount() < 1)
                            || xyCursor == null) {
                        // 如果tb_regex行数小于1，说明并没有数据，之所以没有数据是因为覆盖安装的时候
                        // AlgorithmVersion 和 assetVersion
                        // 的版本相等，导致判断条件不满足，没能解压出init.sql
                        // 所以，如果 tb_regex 为空的话，就把 parseUtilMain 版本更新为 1
                        // (如果是-1，由于判断逻辑不通过并不能更新)
                        /*SDK-674 hewengao 20161114 start*/
                        DuoquUtils.getSdkDoAction().logInfo(Constant.TAG,"ParseItemManager checkHasData.",null);
                        /*SDK-674 hewengao 20161114 end*/
                        JarSubInfoManager.insertOrUpdateJarSubInfo(
                                "parseUtilMain", "1", JarSubInfoManager.USED);
                        SysParamEntityManager.cacheMap.clear();// 清空缓存，否则会用旧数据判断导致错误
                        InitUtil.initAlgorithm();// 解压出init.sql

                        if (FileUtils.isFileExists(Constant.getInidb_PATH())) {
                            updateParse(Constant.getContext());// 写入init.sql，后删除
                        }
                    }
                } catch (Throwable e) {
//                    e.printStackTrace();
                    LogManager.e(Constant.TAG, "checkHasData: ", e);

                } finally {
                    XyCursor.closeCursor(xyCursor, true);
                }
            }
        };
        th.start();

    }

    public static void closeSpecialDatebase() {
        mCurrentSceneId =null;
        mCache.clear();
        close();
        updateUseTime();
    }

    /************************* 一次识别流程中,用于控制读取正则表达式时,只需构造一个db ***********************************/

    static HashMap<Long, SQLiteDatabase> dbMap = new HashMap<Long, SQLiteDatabase>();

    // private static SQLiteDatabase PatternDb=null;
    public synchronized static SQLiteDatabase getPatterDb() {
        long threadId = Thread.currentThread().getId();
        SQLiteDatabase db = dbMap.get(threadId);
        if (db == null || !db.isOpen()) {
            // LogManager.w("duoqu_bizclose",
            // "$$$$$ getPatterDb threadId "+threadId+" db: "+db);
            db = BizportDBManager.getSQLiteDatabase();
            dbMap.put(threadId, db);
        }
        // LogManager.d("duoqu_bizclose",
        // "%%%%% getPatterDb threadId "+threadId+" db: "+db);
        return db;
    }

    private synchronized static void close() {
        long threadId = Thread.currentThread().getId();
        SQLiteDatabase db = dbMap.remove(threadId);
        // LogManager.e("duoqu_bizclose",
        // "close db threadId "+threadId+" db: "+db);
        BizportDBManager.close(db);
    }

    public static void appendUseMatchId(String matchId,String sceneId) {
        try {
            if (StringUtils.isNull(matchId)) return;
            if(mUseMatchIdCache.size() < 400) {
                mUseMatchIdCache.put(matchId, sceneId);
            }
        } catch (Throwable e) {
            LogManager.e(Constant.TAG, "appendUseMatchId ", e);
        }
    }
    
    //删除超时的matchId脚本，3个月没有使用过的matchid为超时
    public static void deleteTimeOutMatchId(String scenId){
    	try {        	
    		//last_use_time <> 0 and
        	StringBuffer whereArgs=new StringBuffer("last_use_time < ?");
    		whereArgs.append(" and scene_id = ? ");
    	    long timeOut = DexUtil.getUpdateCycleByType(OnlineUpdateCycleConfigInterface.TYPE_MATCHID_TIME_OUT_CYCLE, Constant.month*3);
        	long time = (long)(System.currentTimeMillis()-timeOut);
    	    int result = BizportDBManager.delete(TABLE_NAME, whereArgs.toString(), new String[] { 
	                    String.valueOf(time),scenId});
        	
        } catch (Throwable e) {
//            e.printStackTrace();
            LogManager.e(Constant.TAG, "deleteTimeOutMatchId: ", e);

        }
    }
    
    //更新使用过的matchId脚本的时间
    /*SDK-627 hewengao/20160929 start*/
    public static void updateUseTime(){
        if(mUseMatchIdCache.size() <= 0 || System.currentTimeMillis() - mUpdateUseMatchidTime < 90000){
            return ;
        }
        SmartSmsThreadPoolManager.iccidPool.execute(new Runnable() {
            @Override
            public void run() {
                SQLiteDatabase  db =null;
                try {
                    Thread.currentThread().setName("xiaoyuan-ipool"+Thread.currentThread().hashCode());
                    mUpdateUseMatchidTime = System.currentTimeMillis();
                    db = BizportDBManager.getSQLiteDatabase();
                    db.beginTransaction();
                    Map<String,String> dataMap = new HashMap<String,String>(mUseMatchIdCache);
                    mUseMatchIdCache.clear();
                    Set<Map.Entry<String,String>> setData = dataMap.entrySet();
                    String sql = "UPDATE " + TABLE_NAME + " SET " + LAST_USE_TIME
                            + " = " + System.currentTimeMillis() + " WHERE " + MATCH_ID + " = ? and "+SCENE_ID+" = ?";
                    for(Map.Entry<String,String>  entry: setData){
                        db.execSQL(sql,new String[]{entry.getKey(),entry.getValue()});
                    }
                    dataMap.clear();
                    dataMap =null;
                } catch (Throwable e) {
                    LogManager.e(Constant.TAG, "updateUseTime ", e);
                }finally {
                    try {
                        if (db != null) {
                            db.setTransactionSuccessful();
                            db.endTransaction();
                        }
                    }catch (Throwable e){
                        LogManager.e(Constant.TAG, "2updateUseTime ", e);
                    }
                    BizportDBManager.close(db);
                }
            }
        });
    }
    /*SDK-627 hewengao/20160929 end*/

    /*SDK-627 hewengao/20160929 start*/
    static String mCurrentSceneId =null;
    static java.util.concurrent.ConcurrentHashMap<String, String> mCache = new java.util.concurrent.ConcurrentHashMap<String, String>();
    static java.util.concurrent.ConcurrentHashMap<String,String> mUseMatchIdCache= new java.util.concurrent.ConcurrentHashMap<String,String>(400);
    static long mUpdateUseMatchidTime = 0;
    private static String getCacheParsePatternString(String sceneId, String matchId) {
        try {
            return mCache.remove(matchId);
        } catch (Throwable e) {
            //e.printStackTrace();
        }
        return null;
    }

    public static void cacheParsePatternString(final String sceneId,
                                               final String matchId, final int regexType, final SQLiteDatabase db) {

        try {
            if (sceneId.equals(mCurrentSceneId)) {
                return;
            } else {
                mCache.clear();
                mCurrentSceneId = sceneId;
            }
            SmartSmsThreadPoolManager.netWebPool.execute(new Runnable() {

                @Override
                public void run() {
                    /*SDK-633 hewengao 20161009 start*/
                    SmartSmsThreadPoolManager.setThreadNameAndPriority(SmartSmsThreadPoolManager.TNAME_SERVICE_DATA_QUERY, Process.THREAD_PRIORITY_DEFAULT);
                   /*SDK-633 hewengao 20161009 end*/
                    // TODO Auto-generated method stub
                    XyCursor xyCursor = null;
                    /*SDK-630 hewengao/20161002 start*/
                    SQLiteDatabase tempDb= null;
                    try {
                        tempDb= BizportDBManager.getSQLiteDatabase();
                        xyCursor = BizportDBManager
                                .queryPatternString(
                                        tempDb,
                                        false,
                                        TABLE_NAME,
                                        new String[]{REGEX_TEXT, MATCH_ID},
                                        "scene_id = ?  and regex_type = ?",
                                        new String[]{sceneId,
                                                String.valueOf(regexType)}, null, null,
                                        null, null, Constant.getContext());
                        if (xyCursor == null) {
                            return;
                        }
                        while (xyCursor.moveToNext()) {
                            mCache.put(xyCursor.getString(1), xyCursor.getString(0));
                        }
                    } catch (Throwable e) {
                    	//e.printStackTrace();
                    } finally {
                        if (xyCursor != null) {
                            XyCursor.closeCursor(xyCursor, false);
                        }
                        BizportDBManager.close(tempDb);
                    }
                     /*SDK-630 hewengao/20161002 end*/
                }
            });

        } catch (Throwable e) {
            LogManager.e(Constant.TAG, "getParsePatternString: ", e);
        }
        return;
    }
    /*SDK-627 hewengao/20160929 end*/
    public   static String getParsePatternString(String scenId,
            String matchId, int regexType) {

        XyCursor xyCursor = null;
        try {
            // LogManager.d("duoqu_test",
            // "#####getParsePatternString: sceneId: "+scenId+"   matchId: "+matchId+" mRunExeclSql:"+mRunExeclSql);
            // long st = System.currentTimeMillis();
            SQLiteDatabase db = getPatterDb();

            if (mRunExeclSql) {
                /*SDK-674 hewengao 20161114 start*/
                DuoquUtils.getSdkDoAction().logInfo(Constant.TAG,"getParsePatternString in mRunExeclSqlIng scenId:"+scenId+" matchId"+matchId,null);
                /*SDK-674 hewengao 20161114 end*/
                return null;
            }
             /*SDK-627 hewengao/20160929 start*/
            String patterStr = getCacheParsePatternString(scenId,matchId);
            if(patterStr != null){
            	appendUseMatchId(matchId,scenId);
                return patterStr;
            }
            xyCursor = BizportDBManager
                    .queryPatternString(
                            db,
                            false,
                            TABLE_NAME,
                            new String[] { REGEX_TEXT },
                            "scene_id = ? and  match_id = ? and regex_type = ?",
                            new String[] { scenId, matchId
                                   ,String.valueOf(regexType)
                                    }, null, null,
                            null, "1", Constant.getContext());
            if (xyCursor != null && xyCursor.getCount() > 0) {
                int regexIndex = xyCursor.getColumnIndex(REGEX_TEXT);                
                appendUseMatchId(matchId,scenId);
                cacheParsePatternString(scenId, matchId, regexType, db);
                while (xyCursor.moveToNext()) {
                    String regexText = xyCursor.getString(regexIndex);
                    // LogManager.d("duoqu_test",
                    // "$$$$$$getParsePatternString: sceneId: "+scenId+"   matchId: "+matchId+" regexType: "+regexType+" regexText: "+regexText);
                    return regexText;
                }
            } else {
                /*SDK-674 hewengao 20161114 start*/
                DuoquUtils.getSdkDoAction().logInfo(Constant.TAG,"not find PatternStr scenId"+scenId+" matchId:"+matchId,null);
                /*SDK-674 hewengao 20161114 end*/
                checkHasData();
            }
            /*SDK-627 hewengao/20160929 end*/
        } catch (Throwable e) {
//            e.printStackTrace();
            /*SDK-674 hewengao 20161114 start*/
            DuoquUtils.getSdkDoAction().logInfo(Constant.TAG,"error not find PatternStr scenId"+scenId+" matchId:"+matchId,null);
            /*SDK-674 hewengao 20161114 end*/
            LogManager.e(Constant.TAG, "getParsePatternString: ", e);

        } finally {
            if (xyCursor != null) {
                XyCursor.closeCursor(xyCursor, false);
            }
        }
        return null;

    }

    public static void updateStatue(int oldState, int newState) {
        try {
            ContentValues values = new ContentValues();
            values.put(STATE, newState);
            BizportDBManager.update(TABLE_NAME, values, STATE + " = ? ",
                    new String[] { oldState + "" });

        } catch (Throwable e) {
//            e.printStackTrace();
            LogManager.e(Constant.TAG, "updateStatue: ", e);

        } finally {

        }
    }

    private static void deleteStatuedata(int state, Context ctx)
            throws Exception {
        try {
            BizportDBManager.delete(TABLE_NAME, STATE + "=? ",
                    new String[] { state + "" });

        } catch (Throwable e) {
//            e.printStackTrace();
            LogManager.e(Constant.TAG, "deleteStatuedata: ", e);

        } finally {

        }
    }

    private static void handerLine(String line, SQLiteDatabase db) {

        if (!StringUtils.isNull(line)) {
            String sqlhead = "";
            String remain = "";
            if (line.indexOf("values") != -1) {
                sqlhead = line.substring(0, line.indexOf("values"));
                remain = line.replace(sqlhead, "");
                sqlhead = sqlhead + " values ";
                remain = remain.replace("values", "");
            } else {
                return;
            }

            String str[] = remain.split("'\\),\\('");

            List<String> sqlList = new ArrayList<String>();

            if (str != null && str.length > 0) {
                for (int i = 0; i < str.length; i++) {
                    if (!StringUtils.isNull(str[i])) {
                        String item = str[i].trim();
                        if (item.startsWith("(")) {
                            sqlList.add(sqlhead + " " + "" + item + "')");

                        } else if (item.endsWith(";")) {

                            sqlList.add(sqlhead + " " + "('" + item + "");

                        } else if (item.endsWith(")")) {

                            sqlList.add(sqlhead + " " + "('" + item + "')");
                        } else {
                            sqlList.add(sqlhead + " " + "('" + item + "')");

                        }

                    }
                }
            }

            if (!sqlList.isEmpty()) {
                for (int i = 0; i < sqlList.size(); i++) {
                    // PrintTestLogUtil.printTestLog("updateparse",
                    // "handerLine line="+sqlList.get(i));
                    String item = sqlList.get(i);
                    if (!StringUtils.isNull(item)) {
                        try {
                            db.execSQL(item);
                        } catch (Throwable e) {
//                            e.printStackTrace();
                            LogManager.e(Constant.TAG, "handerLine: ", e);
                        }

                    }

                }
            }

        }

    }

    private static boolean mRunExeclSql = false;

    public static void updateParse(Context context) {
        String filePath = Constant.getInidb_PATH();// filePath更新文件的路径，假如更新文件存在，则需要执行更新流程
        if (!FileUtils.isFileExists(filePath)) {
            return;

        }
        SQLiteDatabase db = null;
        try {
            // 更新数据库状态
            updateStatue(NORMAL, NEEDDEL);
            mRunExeclSql = true;
            BizportDBManager.excSql(filePath, false);
            mRunExeclSql = false;
            // 删除数据库里的旧数据
            deleteStatuedata(NEEDDEL, Constant.getContext());
            // 删除数据文件
            FileUtils.deleteAllFile(filePath);
        } catch (Throwable e) {
            // e.printStackTrace();
            // 中途出错了，还原旧数据
            updateStatue(NEEDDEL, NORMAL);
        } finally {
            mRunExeclSql = false;
            BizportDBManager.closeDB(filePath, true, null, null, db);
        }
        // }

    }

    public static boolean execNqSql = false;

    /* SDK-396 huangzhiqiang 20160418 start */
    // 更新内嵌数据
    public static boolean updateNeiQianSql(Context context) {
        try {
            String filePath = Constant.getNQSQL_PATH();// filePath更新文件的路径，假如更新文件存在，则需要执行更新流程
            File file = new File(filePath);
            if (!file.exists()) {
                return false;
            }
            execNqSql = true;
            return DBManager.excSql(file, true);
        } catch (Throwable e) {
            LogManager.e(Constant.TAG, "updateNeiQianSql: ", e);
        } finally {
            execNqSql = false;
        }
        return false;
    }
    /* SDK-396 huangzhiqiang 20160418 end */

    public static void deleteAll() {
        try {
            BizportDBManager.delete(TABLE_NAME, null, null);

        } catch (Throwable e) {
//            e.printStackTrace();
            LogManager.w(Constant.TAG, "deleteAll: ", e);

        }
    }

    /**
     * 删除状态为初始化临时标记并重复的数据
     */
    public static void deleteRepeatData() {
        SQLiteDatabase db = null;
        try {
            db = BizportDBManager.getSQLiteDatabase();
            db.execSQL("DELETE FROM tb_regex WHERE state="
                    + INITTAG
                    + " AND match_id IN (SELECT match_id FROM tb_regex GROUP BY match_id HAVING COUNT(match_id) > 1)");
        } catch (Throwable e) {
//            e.printStackTrace();
            LogManager.w(Constant.TAG, "deleteRepeatData: ", e);

        } finally {
            BizportDBManager.close(db);
        }
    }
    
    
    public static String queryPubIdByPhoneNum(String phoneNum) {
    	return ParsePhonePubIdService.queryPubIdByPhoneNum(phoneNum);
    }

    /* SDK-695 huangzhiqiang 20161207 begin */
    /**
     * 检测正则库是否已损坏
     * 
     * return true:已损坏 false:未损坏
     */
    private static boolean databaseIsCorrupt() {
        Context ctx = Constant.getContext();
        return ctx != null && ctx.getDatabasePath("bizport.db-corrupted").exists();
    }

    /**
     * 删除损坏的正则库文件
     */
    private static void deleteCorruptFile() {
        try {
            Context ctx = Constant.getContext();
            ctx.getDatabasePath("bizport.db-corrupted").delete();
            ctx.getDatabasePath("bizport.db-journalcorrupted").delete();
        } catch (Throwable e) {
            LogManager.e(Constant.TAG, "InitUtil deleteCorruptFile error", e);
        }
    }
    /* SDK-695 huangzhiqiang 20161207 end */
}
